<template>
  <view class="date-time-picker" v-if="visible">
    <view class="date-time-mask" @click.stop="hide"></view>
    <view class="date-time-container" @click.stop="handleEvent">
      <view class="time-picker-tool" v-if="isShowToolBar">
        <view :class="[cancelButtonClass]" @click.stop="cancel">
          <text>{{ cancelButtonText }}</text>
        </view>
        <view :class="[toolBarTitleClass]">
          <text>{{ toolBarTitle }}</text>
        </view>
        <view :class="[confirmButtonClass]" @click.stop="confirm">
          <text>{{ confirmButtonText }}</text>
        </view>
      </view>
      <picker-view
        class="picker-view"
        :indicator-style="indicatorStyleString"
        :value="dateTime"
        @change="dateTimePickerChange"
      >
        <picker-view-column data-id="year" v-if="isShowYear">
          <view class="item" v-for="(item, index) in years" :key="index"
            >{{ item }}年</view
          >
        </picker-view-column>
        <picker-view-column data-id="month" v-if="isShowMonth">
          <view class="item" v-for="(item, index) in months" :key="index"
            >{{ item }}月</view
          >
        </picker-view-column>
        <picker-view-column data-id="day" v-if="isShowDay">
          <view class="item" v-for="(item, index) in days" :key="index"
            >{{ item }}日</view
          >
        </picker-view-column>
        <picker-view-column data-id="hour" v-if="isShowHour">
          <view class="item" v-for="(item, index) in hours" :key="index"
            >{{ item }}时</view
          >
        </picker-view-column>
        <picker-view-column data-id="minute" v-if="isShowMinute">
          <view class="item" v-for="(item, index) in minutes" :key="index"
            >{{ item }}分</view
          >
        </picker-view-column>
        <picker-view-column data-id="second" v-if="isShowSecond">
          <view class="item" v-for="(item, index) in seconds" :key="index"
            >{{ item }}秒</view
          >
        </picker-view-column>
      </picker-view>
    </view>
  </view>
</template>

<script>
import {
  getOneMonthDays,
  getTimeArray,
  addZero,
  getIndexOfArray,
} from './uitls/util.js';
export default {
  name: 'DateTimePicker',
  props: {
    startYear: {
      type: Number,
      default: 1900,
    },
    endYear: {
      type: Number,
      default: new Date().getFullYear(),
    },
    isShowToolBar: {
      type: Boolean,
      default: true,
    },
    cancelButtonText: {
      type: String,
      default: '取消',
    },
    cancelButtonClass: {
      type: String,
      default: 'cancel-btn',
    },
    toolBarTitle: {
      type: String,
      default: '请选择',
    },
    toolBarTitleClass: {
      type: String,
      default: 'tool-title',
    },
    confirmButtonText: {
      type: String,
      default: '确定',
    },
    confirmButtonClass: {
      type: String,
      default: 'confirm-btn',
    },
    datestring: {
      type: String,
      default: '',
    },
    type: {
      /**
       * date 年月日
       * year-month 年月
       * year 年
       * datetime 年月日 时分
       * datetime-all 年月日 时分秒
       * time 时分秒
       * hour-minute 时分
       */
      type: String,
      default: 'date',
    },
    indicatorStyle: {
      type: Object,
      default: null,
    },
  },
  data() {
    return {
      visible: false,
      dateTime: [],
      days: [],
      indicatorStyleString: '',
    };
  },
  watch: {
    indicatorStyle(val) {
      this.getIndicatorStyle();
    },
    type() {
      this.initDateTime();
    },
    datestring() {
      this.initDateTime();
    },
  },
  computed: {
    years() {
      return this.initTimeData(this.endYear, this.startYear);
    },
    isShowYear() {
      return this.type !== 'time' && this.type !== 'hour-minute';
    },
    months() {
      return this.initTimeData(12, 1);
    },
    isShowMonth() {
      return (
        this.type !== 'year' &&
        this.type !== 'time' &&
        this.type !== 'hour-minute'
      );
    },
    isShowDay() {
      return (
        this.type === 'date' ||
        this.type === 'datetime' ||
        this.type === 'datetime-all'
      );
    },
    hours() {
      return this.initTimeData(23, 0);
    },
    isShowHour() {
      return (
        this.type !== 'date' &&
        this.type !== 'year-month' &&
        this.type !== 'year'
      );
    },
    minutes() {
      return this.initTimeData(59, 0);
    },
    isShowMinute() {
      return (
        this.type !== 'date' &&
        this.type !== 'year-month' &&
        this.type !== 'year'
      );
    },
    seconds() {
      return this.initTimeData(59, 0);
    },
    isShowSecond() {
      return this.type === 'datetime-all' || this.type === 'time';
    },
  },
  methods: {
    getIndicatorStyle() {
      if (this.indicatorStyle) {
        for (let key in this.indicatorStyle) {
          this.indicatorStyleString += `${key}:${this.indicatorStyle[key]};`;
        }
      }
    },
    handleEvent() {
      return;
    },
    cancel() {
      this.hide();
    },
    confirm() {
      this.formatDate();
      this.hide();
    },
    show() {
      this.visible = true;
    },
    hide() {
      this.visible = false;
    },
    initDateTime() {
      let value;
      if (this.datestring.length > 0) {
        if (this.type === 'year') {
          value = new Date(this.datestring, 0);
        } else if (this.type === 'time' || this.type === 'hour-minute') {
          let date = new Date();
          let ary = this.datestring.split(':');
          ary.forEach((item, index) => {
            if (index == 0) {
              date.setHours(item);
            } else if (index == 1) {
              date.setMinutes(item);
            } else if (index == 2) {
              date.setSeconds(item);
            }
          });
          value = date;
        } else {
          value = new Date(this.datestring.replace(/-/g, '/'));
        }
      } else {
        value = new Date();
      }
      let len, timeArray, index;
      let array = getTimeArray(value);
      let [year, month, day, hour, minute, second] = array;
      this.days = this.initTimeData(getOneMonthDays(year, month - 1), 1);
      let names = ['year', 'month', 'day', 'hour', 'minute', 'second'];
      switch (this.type) {
        case 'date':
          len = 3;
          break;
        case 'year-month':
          len = 2;
          break;
        case 'year':
          len = 1;
          break;
        case 'datetime':
          len = 5;
          break;
        case 'datetime-all':
          len = 6;
          break;
        case 'time':
          len = 3;
          break;
        case 'hour-minute':
          len = 2;
          break;
      }
      timeArray = new Array(len).fill(0);
      if (this.type === 'time' || this.type === 'hour-minute') {
        names = names.slice(3);
        array = array.slice(3);
      }
      timeArray = timeArray.map((item, index) => {
        const name = names[index];
        return getIndexOfArray(array[index], this[name + 's']);
      });
      this.dateTime = timeArray;
    },
    initTimeData(end, start) {
      let timeArray = [];
      while (start <= end) {
        timeArray.push(start);
        start++;
      }
      return timeArray;
    },
    formatDate() {
      let names = ['year', 'month', 'day', 'hour', 'minute', 'second'];
      let dateString,
        formatDateArray = [];
      if (
        this.type === 'date' ||
        this.type === 'year-month' ||
        this.type === 'year'
      ) {
        formatDateArray = this.dateTime.map((item, index) => {
          return this[names[index] + 's'][item] < 10
            ? addZero(this[names[index] + 's'][item])
            : this[names[index] + 's'][item];
        });
        dateString = formatDateArray.join('-');
      } else if (this.type === 'time' || this.type === 'hour-minute') {
        names = names.splice(3);
        formatDateArray = this.dateTime.map((item, index) => {
          return this[names[index] + 's'][item] < 10
            ? addZero(this[names[index] + 's'][item])
            : this[names[index] + 's'][item];
        });
        dateString = formatDateArray.join(':');
      } else {
        let name1 = names.splice(0, 3);
        formatDateArray = this.dateTime.map((item, index) => {
          if (index > 2) {
            return this[names[index - 3] + 's'][item] < 10
              ? addZero(this[names[index - 3] + 's'][item])
              : this[names[index - 3] + 's'][item];
          } else {
            return this[name1[index] + 's'][item] < 10
              ? addZero(this[name1[index] + 's'][item])
              : this[name1[index] + 's'][item];
          }
        });
        dateString =
          formatDateArray.splice(0, 3).join('-') +
          ' ' +
          formatDateArray.join(':');
      }
      this.$emit('change', dateString);
    },
    dateTimePickerChange(e) {
      let columns = e.target.value;
      if (
        this.type === 'date' ||
        this.type === 'datetime' ||
        this.type === 'datetime-all'
      ) {
        this.dateTime.splice(0, 1, columns[0]);
        if (columns[0] != this.dateTime[0]) {
          this.days = this.initTimeData(
            getOneMonthDays(
              this.years[this.dateTime[0]],
              this.months[this.dateTime[1]],
            ),
            1,
          );
          if (this.dateTime[1] == 1) {
            if (this.dateTime[2] === this.days.length - 1) {
              if (
                getOneMonthDays(this.years[columns[0]], this.dateTime[1]) <
                getOneMonthDays(this.years[this.dateTime[0]], this.dateTime[1])
              ) {
                this.dateTime.splice(2, 1, this.days.length - 1);
              }
            }
          }
        } else {
          this.dateTime.splice(1, 1, columns[1]);
          this.days = this.initTimeData(
            getOneMonthDays(this.years[this.dateTime[0]], this.dateTime[1]),
            1,
          );
          if (columns[1] != this.dateTime[1]) {
            if (this.dateTime[1] == 1) {
              if (this.dateTime[2] === this.days.length - 1) {
                if (
                  getOneMonthDays(this.years[columns[0]], this.dateTime[1]) <
                  getOneMonthDays(
                    this.years[this.dateTime[0]],
                    this.dateTime[1],
                  )
                ) {
                  this.dateTime.splice(2, 1, this.days.length - 1);
                }
              }
            } else {
              if (this.dateTime[2] > this.days.length - 1) {
                this.dateTime.splice(2, 1, this.days.length - 1);
              } else {
                this.dateTime.splice(2, 1, columns[2]);
              }
            }
          } else {
            this.dateTime.splice(2, 1, columns[2]);
          }
        }
        if (columns.length > 2) {
          columns.splice(3).forEach((column, index) => {
            this.dateTime.splice(index + 3, 1, column);
          });
        }
      } else {
        columns.forEach((column, index) => {
          this.dateTime.splice(index, 1, column);
        });
      }
      if (!this.isShowToolBar) {
        this.formatDate();
      }
    },
  },
  mounted() {
    this.getIndicatorStyle();
    this.initDateTime();
  },
};
</script>

<style lang="scss" scoped>
.date-time-picker {
  .date-time-mask {
    position: fixed;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    background-color: rgba($color: #000000, $alpha: 0.5);
    z-index: 998;
  }

  .date-time-container {
    position: fixed;
    height: 50%;
    bottom: 0;
    right: 0;
    left: 0;
    background-color: #f6f6f6;
    z-index: 1000;
    display: flex;
    flex-direction: column;

    .time-picker-tool {
      height: 80rpx;
      display: flex;
      align-items: center;
      justify-content: space-between;
      font-size: 28rpx;

      .cancel-btn {
        padding: 0 28rpx;
        box-sizing: border-box;
        color: #969799;
        font-size: 32rpx;
      }

      .tool-title {
        font-weight: 500;
        font-size: 16px;
        max-width: 50%;
        overflow: hidden;
        white-space: nowrap;
        text-overflow: ellipsis;
        display: none;
      }

      .confirm-btn {
        padding: 0 28rpx;
        box-sizing: border-box;
        color: #007aff;
        font-size: 32rpx;
      }
    }

    .picker-view {
      width: 100%;
      flex: 1;

      .item {
        font-size: 34rpx;
        display: flex;
        align-items: center;
        justify-content: center;
      }
    }
  }
}
.uni-picker-view-indicator {
  background: none !important;
}
</style>
